package com.gitee.openviducn.inspector.auth;

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTCreator;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.auth0.jwt.interfaces.JWTVerifier;
import com.auth0.jwt.interfaces.Verification;
import com.google.common.collect.Maps;

import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Date;
import java.util.Map;
import java.util.Objects;

/**
 * TOKEN生成和校验
 * @Author: https://gitee.com/wesleyOne
 * @Date: 02.28 2020
 */
public class JwtUtil {

    private static final int EXPIRE_TIME = 7 * 24 * 60 * 60 ;
    private static final String DEFAULT_SECRET = "inspector_cn";

    /**
     * 校验token是否正确
     *
     * @param claims     参数集
     * @param token     密钥
     * @param secret    密码
     * @return 是否正确
     */
    public static boolean verify(Map<String, String> claims, String token, String secret) {
        try {
            if (Objects.isNull(secret)) {
                secret = DEFAULT_SECRET;
            }
            //根据密码生成JWT效验器
            Algorithm algorithm = Algorithm.HMAC256(secret);
            Verification require = JWT.require(algorithm);
            claims.keySet().forEach(key -> require.withClaim(key, claims.get(key)));
            JWTVerifier verifier = require.build();
            //效验TOKEN
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     */
    private static String getByToken(String token, String key) {
        if (Objects.isNull(token)) {
            return null;
        }
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim(key).asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获取token中的过期时间
     */
    public static Date getExpires(String token) {
        if (Objects.isNull(token)) {
            return null;
        }
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getExpiresAt();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名
     *
     * @param claims 参数集
     * @param secret   密码
     * @return 加密的token
     */
    public static String signWithExpireTime(Map<String, String> claims, String secret, Integer expireSeconds) {
        if (Objects.isNull(secret)) {
            secret = DEFAULT_SECRET;
        }
        if (Objects.isNull(expireSeconds)) {
            expireSeconds = EXPIRE_TIME;
        }
        long expireMillis = LocalDateTime.now().plusSeconds(expireSeconds).atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
        Date date = new Date(expireMillis);

        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTCreator.Builder builder = JWT.create();
        claims.keySet().forEach(key -> builder.withClaim(key, claims.get(key)));
        return builder.withExpiresAt(date)
                .sign(algorithm);
    }

    /**
     * 生成签名 无过期时间
     *
     * @param claims 参数集
     * @param secret   密码
     * @return 加密的token
     */
    public static String sign(Map<String, String> claims, String secret) {
        if (Objects.isNull(secret)) {
            secret = DEFAULT_SECRET;
        }
        Algorithm algorithm = Algorithm.HMAC256(secret);
        JWTCreator.Builder builder = JWT.create();
        claims.keySet().forEach(key -> builder.withClaim(key, claims.get(key)));
        return builder.sign(algorithm);
    }

    /**
     * 获取token中的所有claims
     */
    public static Map<String, String> getClaims(String token) {
        if (Objects.isNull(token)) {
            return null;
        }
        try {
            DecodedJWT jwt = JWT.decode(token);
            Map<String, Claim> claims = jwt.getClaims();
            Map<String, String> result = Maps.newHashMap();
            for (String key : claims.keySet()) {
                result.put(key, claims.get(key).asString());
            }
            return result;
        } catch (JWTDecodeException e) {
            return null;
        }
    }
}
